﻿//-----------------------------------------------------------------------
// <copyright file="ProcessPerfCounterViewModel.cs" author="Artak Mkrtchyan">
//     Creative Commons - GNU General Public License (http://creativecommons.org/licenses/GPL/2.0/
// </copyright>
// <author>Artak Mkrtchyan</author>
// <email>mkArtak@gmail.com</email>
// <date>29/03/2013</date>
//-----------------------------------------------------------------------

using ConsoleHoster.Common.Utilities;
using ConsoleHoster.Common.Utilities.Threading;
using ConsoleHoster.Common.ViewModel;
using ConsoleHoster.Model;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;

namespace ConsoleHoster.ViewModel.ControlVM
{
	public sealed class ProcessPerfCounterViewModel : ViewModelBase, IDisposable
	{
		public const int ProbeHistoryLength = 10;

		private readonly IPerformanceCounterValueProvider performanceCounterValueProvider;
		private readonly ObservableCollection<int> probes = new ObservableCollection<int>();
		private ITimer timer;
		private readonly Object probesSyncer = new Object();

		public ProcessPerfCounterViewModel(string argProcessName, IDispatcher argDispatcher, ILogger argLogger)
			: this(new ProcessCpuPerformanceCounterValueProvider(argProcessName), new FrameworkTimer(TimeSpan.FromSeconds(1)), argDispatcher, argLogger)
		{
		}

		internal ProcessPerfCounterViewModel(IPerformanceCounterValueProvider argPerfCounterValueProvider, ITimer argTimer, IDispatcher argDispatcher, ILogger argLogger)
			: base(argDispatcher, new ComponentLogger("ProcessPerfCounterViewModel", argLogger))
		{
			ValidationManager.RequireArgumentNotNull(argPerfCounterValueProvider, "argPerfCounterValueProvider");
			ValidationManager.RequireArgumentNotNull(argTimer, "argTimer");

			this.performanceCounterValueProvider = argPerfCounterValueProvider;
			this.timer = argTimer;

			this.timer.Tick += new EventHandler(this.OnTimerElapsed);
		}

		private void OnTimerElapsed(object sender, EventArgs e)
		{
			try
			{
				int tmpValue = this.performanceCounterValueProvider.GetCounterValue();
				this.AddNextProbe(tmpValue);
			}
			catch
			{
			}
		}

		public void StartProbing()
		{
			this.timer.Start();
		}

		public void StopProbing()
		{
			this.timer.Stop();
		}

		public void Dispose()
		{
			this.StopProbing();
			this.timer.Tick -= new EventHandler(this.OnTimerElapsed);

			this.timer.Dispose();
			this.performanceCounterValueProvider.Dispose();
		}

		private void AddNextProbe(int argProbeValue)
		{
			this.RunActionOnUIThread(() =>
			{
				lock (this.probesSyncer)
				{
					this.Probes.Add(argProbeValue);
					if (this.Probes.Count > ProcessPerfCounterViewModel.ProbeHistoryLength)
					{
						this.Probes.RemoveAt(0);
					}
				}
				this.NotifyPropertyChange("LastValue");
			});
		}

		public ObservableCollection<int> Probes
		{
			get
			{
				return this.probes;
			}
		}

		public int LastValue
		{
			get
			{
				lock (this.probesSyncer)
				{
					return this.probes.Any() ? this.probes.Last() : 0;
				}
			}
		}

		public TimeSpan ProbeInterval
		{
			get
			{
				return this.timer.Interval;
			}
			set
			{
				this.timer.Interval = value;
			}
		}
	}
}
